local Armature = require("app.public.avatar.Armature")
local EffectFactory = import(".EffectFactory")

local Effect = class("Effect",function() return cc.Node:create() end)

function Effect:ctor(params)
    self.effectId = params.effectId
    self.linkerEffectIndex = params.linkerEffectIndex
    local isLinkerEffect = self.linkerEffectIndex > 0

	self.dir = params.dir or 1
    local cfg = params.objectConfig
    self.armaturesDir = "armatures/"..cfg:getDir()
    self.armaturesName = cfg:getArmatureName()
    self.animationName = cfg:getAnimation()
    if isLinkerEffect then
        self.linkerEffect, self.runLineActionFunc = EffectFactory:createLinkerEffect(self.linkerEffectIndex)
        self:addChild(self.linkerEffect)
        self.linkerEffect:setCascadeOpacityEnabled(true)
    end

    if string.len(self.animationName) > 0 then
        local armature = Armature.create({path=self.armaturesDir,armatureName=self.armaturesName,animationName=""})
        if armature then
            self:setArmature(armature)
        else
            printError("effect armature create Error!!!!! animation info:",self.armaturesDir,self.armaturesName,self.animationName)
        end
    end

    self:updateDir()
    -- self.sfxFilePath = params.sfxFilePath
    
    local function onNodeEvent(event)
        if "enter" == event then
            self:onEnter()
        elseif "exit" == event then
            self:onExit()
        elseif "cleanup" == event then
            self:onCleanup()
        end
    end
    self:registerScriptHandler(onNodeEvent) 
end

function Effect:setEffectOpacity(opacity)
    if self._armature then
        self._armature:setOpacity(opacity)
    end
    if self.linkerEffect then
        self.linkerEffect:setOpacity(opacity)
    end
end

function Effect:setSfxFilePath(sfxFilePath)
    self.sfxFilePath = sfxFilePath
end

function Effect:onEnter()
    
end

function Effect:onExit()
    --effect如果放到actor上，actor从父节点移除时会调用到这个方法，所以不在这里处理，在cleanup里面去处理
    -- print("==========Effect:onExit=======id:",self.effectId)
end

function Effect:onCleanup()
    --print("==========Effect:onCleanup=======id:",self.effectId)
    if self.sfxAudioId then
        AM.stop(self.sfxAudioId)
        self.sfxAudioId = nil
    end
end


function Effect:getEffectId()
    return self.effectId
end

function Effect:setArmature(armature)
    if not cc.isDead(self._armature) then
        self._armature:removeAllEventListeners()
        self:removeChild(self._armature)
        self._armature = nil
    end
    if not cc.isDead(armature) then
        self._armature = armature
        self:addChild(self._armature)
    end
end

function Effect:getArmature()
    return self._armature
end

function Effect:setRemoveCallBack(callback)
    self.removeCallBack = callback
end

function Effect:setParentRemoveCallBack(callback)
    self.parentRemoveCallBack = callback
end

function Effect:turn(towards)
    if towards == Enums.Face.left then
        --面朝左
        self:turnLeft()
    elseif towards == Enums.Face.right then
        --面朝右
        self:turnRight()
    end
end

function Effect:turnLeft()
    self:face(-1)
end

function Effect:turnRight()
   self:face(1)
end

function Effect:facing()
    return self.dir
end

function Effect:face(facing)
    if self.dir ~= facing then
        self.dir = facing
        self:updateDir()
    end
end

function Effect:updateDir()
    local armature = self._armature
    if armature then
        local scaleX = math.abs(armature:getScaleX())
        armature:setScaleX(scaleX*-self.dir)
    end
end

function Effect:setX(x)
    -- print("----------x:"..x)
    self:setPositionX(x)
end

function Effect:playDefault()
    if not cc.isDead(self._armature) then
        self:playAni({name=self.animationName})
    end

    local sound = self.sfxFilePath
    if sound then
--        print("----------------sound:", sound)
        self.sfxAudioId = AM.play(sound, true)
        if self._volume and self.sfxAudioId then
            AM.setVolume(self.sfxAudioId, self._volume)
        end
    end
end

function Effect:playDefaultForLinkerEffect(victim, onceCallBack)
    if self.linkerEffect then
        self.linkerEffect:setVisible(true)
        local posX,posY = self.linkerEffect:toWorldPosition(0,0)
        self.linkerEffect:setEndPos(posX,posY)
        self.linkerEffect:stopActionByTag(Enums.CommonActionTag.BattleLinkerAction)
        self.linkerEffect:stopActionByTag(Enums.CommonActionTag.BattleLinkerEndAction)
        self.startTime = app:getUTCTime()

        local index = self.linkerEffectIndex
        if Res.LinkerEffectConfig[index] == nil then
            --如果为空就取第一个
            index = 1
        end
        local params = Res.LinkerEffectConfig[index]

        local maxDT =  params.moveTime or 0.05
        if victim then
            local sequence = cc.Sequence:create(cc.DelayTime:create(0), cc.CallFunc:create(function() 
                local posX,posY = 0,0
                local param = "body"
                if victim and not tolua.isnull(victim) then
                    posX,posY = victim:getBonePos(param)
                    local passTime = app:getUTCTime() - self.startTime
                    if passTime > maxDT then
                        self.linkerEffect:setEndPos(posX,posY)
                    else
                        local posX1,posY1= self.linkerEffect:toWorldPosition(0,0) 
                        posX = posX1 + (posX - posX1)*passTime/maxDT
                        posY = posY1 + (posY - posY1)*passTime/maxDT
                        self.linkerEffect:setEndPos(posX,posY)
                    end
                else
                    self.linkerEffect:setVisible(false)
                end
            end))
            local action = cc.RepeatForever:create(sequence)
            action:setTag(Enums.CommonActionTag.BattleLinkerAction)
            self.linkerEffect:runAction(action)

            if onceCallBack then
                local actions = {}
                table.insert(actions, cc.DelayTime:create(params.lineMaxFrame*Constant.BattleLineAnimDelayPerUnit))
                table.insert(actions, cc.CallFunc:create(onceCallBack))
                local action1 = cc.Sequence:create(actions)
                action1:setTag(Enums.CommonActionTag.BattleLinkerEndAction)
                self.linkerEffect:runAction(action1)

                --只播放一次帧动画，需要重置动画从头开始
                local func = self.runLineActionFunc
                if func then
                    func()
                end
            end
        else
            if onceCallBack then
                onceCallBack()
            end
        end
    end
end

function Effect:setVolume(volume)
    self._volume = volume
end

function Effect:removeSelf(isCleanUp)
    if self.sfxAudioId then
        --print("====removeSelf=self.sfxAudioId")
        AM.stop(self.sfxAudioId)
        self.sfxAudioId = nil
    end

    if self.linkerEffect then
        self.linkerEffect:setVisible(false)
    end

    if self.removeCallBack then
        self.removeCallBack()
    end
    self.removeCallBack = nil

    if self.parentRemoveCallBack then
    	self.parentRemoveCallBack()
    end
    self.parentRemoveCallBack = nil

    self:stopAllActions()
    local parent = self:getParent()
    if parent then
        parent:removeChild(self, isCleanUp)
    end
    -- self:removeFromParentAndCleanup(false)
end

function Effect:playAni(params)
    if not cc.isDead(self._armature) then
        if params then
            -- 临时修改，所有角色fadeIn效果移除
            params.fadeInTime = 0

            return self._armature:playAni(params)
        else
            self._armature:play()
            return true
        end
    else
        self._armature = nil
    end
end

function Effect:playOnce(callbackFn)
    local isHasArmature = not cc.isDead(self._armature)
    local isHasSound = (self.sfxFilePath ~= nil)
    local isLinkerEffect = self.linkerEffectIndex > 0

    if (not isHasArmature) and (not isHasSound) and (not isLinkerEffect) then
        --如果没有动画或者音乐
        callbackFn()
        return true
    end

    local sound = self.sfxFilePath
    if sound then
        local audioId = AM.play(sound, false, nil, nil)
        if self._volume and audioId then
            AM.setVolume(audioId,self._volume)
        end
        -- if not audioId then
        --     --如果没有创建出声音
        --     printError("Effect sfx play error!!!! sfxFilePath:",sound)
        -- end
    end
    
    if isHasArmature then
        -- self:playAni({name=name,playTimes = 1,completeCallback = callbackFn})
        local isImmediateCallBack = false
        local function aniEnd()
            callbackFn()
            isImmediateCallBack = true
        end
        self:playAni({name=self.animationName, playTimes = 1, completeCallback = aniEnd})
        if isImmediateCallBack then
            return true
        end
    elseif isLinkerEffect then
        return false
    else
        callbackFn()
        return true
    end

    return false
end

function Effect:dumpInfo()
    -- print("dump info: ReferenceCount:",self:getReferenceCount())
    print("Effect id:", self.effectId)
    if self._armature then
        -- print("dump info: armature ReferenceCount:",self._armature:getReferenceCount())
        print("self.armaturesDir:",self.armaturesDir)
        print("self.armaturesName:",self.armaturesName)
    end
end

local Display_getArmature = db.CCArmatureDisplay.getArmature
function Effect:clearAnimation()
    if not cc.isDead(self._armature) and not cc.isDead(Display_getArmature(self._armature)) then
        local animation = self._armature:getAnimation()
        if animation then
            animation:reset()
        end
    end
end

return Effect